#include <windows.h>
#include <string.h>

#include "lib.h"
#include "patch.h"
#include "dloadpkg.h"
#include "client.h"
#include "file.h"
#include "patchsrv.h"
#include "pkglist.h"
#include "pkgdesc.h"

// Send a requested packages  (send-only protocol)
//
// Request:
//
// <msg len><D><pkg name>
//
// Responses to this protocol request are:
//
// <3><E><initial error>
//
//	or
//
// <10><S><4byte pkg ver><4byte zip len>
//		<4><D><2byte len><data block>
//			.
//			.
//		<4><D><2byte len><data block>
//			or
//		<3><E><error after initial success>
//
// Descriptions:
//
// <initial error>
//		EM_ServerDownForMaintenance:  generated in DetermineRequest
//		EM_UnknownPackage:			  requested pkg doesn't exist in list
//		EM_ZipDataError:			  pkg exists in list but can't open
//
//	<error after initial success>
//		EM_ZipDataError:	problem reading pkg file
//
// No other errors are possible.
//

enum DLPkgStates { DONE, SEND_HEADER, SEND_DATA };

#define FILEHEADERSIZE	14
#define DATAHEADERSIZE	4

DownloadPackage::DownloadPackage(Client* client)
	: Protocol(client)
{
	state = DONE;
}

bool8
DownloadPackage::recognize(uint8* Msg, uint32 Len)
{
	bool8 success;

	m_multibyte = false;
	success = (bool8)(Msg[0] == 'D' && Len > 1);
	if (!success)
	{
		success = (bool8)(((*(uint16*)&Msg[0]) == *(uint16*)"MD") && Len > 2);
		if (success)
			m_multibyte = true;
	}
	return success;
//	return (bool8)(Msg[0] == 'D' && Len > 1);
}

int32
DownloadPackage::start(uint8* Msg, uint32 Len)
{
	PackageList* list;
	PackageDescription* item;
	String filename;
	int32 result = EM_UnknownPackage;
	
	list = PatchServer::This->getPackageList();
	if (list)
	{
		if (m_multibyte)
		{
			filename.deserialize(Msg + 2);
		}
		else
		{
			char fname[MAX_PATH];
			if (Len - 1 >= MAX_PATH)
				Len = MAX_PATH;
			strncpy(fname, (char*)Msg + 1, Len - 1);
			fname[Len - 1] = '\0';
			filename = fname;
		}

		item = list->getItem(0);
		while (item && 0 != item->getName().caseCompare(filename))
			item = item->getNext();

		if (item)
		{
			if (client->getFile()->open(item->getZipName()))
			{
				if (PatchServer::This->getPortIO()->newPortUser(
					client->getFile()))
				{
					pkgver = item->getVersion();
					pkgsize = item->getZipSize();
					state = SEND_HEADER;

					result = EM_Success;
				}
				else
					client->getFile()->close();
			}
			else
				result = EM_ZipDataError;
		}
		PatchServer::This->releasePackageList();
	}
	return result;
}

void
DownloadPackage::netIn(int32 Amt)
{
	// start protocol...DownloadPackage will not post a network read during
	// the lifetime of the protocol.
	//
	if (state == SEND_HEADER)
	{
		client->getFile()->read(
			client->getOBuf() + FILEHEADERSIZE,
			PACKETSIZE - FILEHEADERSIZE);
	}
	else if (state == SEND_DATA && Amt == 0)
	{
		client->getFile()->read(
			client->getOBuf() + DATAHEADERSIZE,
			PACKETSIZE - DATAHEADERSIZE);
	}
	else
	{	
		int32 ieat = 0, overhead = 1;
		if (client->getIBuf()[0] == 0)
		{
			overhead = 3;
			ieat = client->msgGet(client->getIBuf()+1, (uint16*)0)+1;
		}
		else
			ieat = client->msgGet(client->getIBuf(), (uint8 *)0);

		uint8* msg = client->getIBuf() + overhead;

		if (msg[0] == 'S')
		{
			int32 bytespersecond = client->msgGet(&msg[1], (uint16 *)0);

			client->setBytesPerSecond(bytespersecond);
	
			client->eatIBuf(Amt);
		}

		netIn(0);	//read the rest of the SEND_DATA
	}
		
}

void
DownloadPackage::netOut(int32 /*Amt*/)
{
	if (client->isDatatoRead(6, 3, 'S'))
		client->readNet();
	else
		netIn(0);

}

void
DownloadPackage::fileIn(int32 Amt)
{
	if (state == SEND_DATA)
	{
		uint8* obuf = client->getOBuf();

		obuf[0] = (uint8)0x04;
		obuf[1] = (uint8)'D';
		obuf[2] = (uint8)((Amt >> 8) & 0xff);
		obuf[3] = (uint8)(Amt & 0xff);

		client->setOUsed(4 + Amt);
		client->writeNet();
	}
	else	// SEND_HEADER
	{
		uint8* obuf = client->getOBuf();

		obuf[0] = (uint8)0x0a;
		obuf[1] = (uint8)'S';
		obuf[2] = (uint8)((pkgver >> 24) & 0xff);
		obuf[3] = (uint8)((pkgver >> 16) & 0xff);
		obuf[4] = (uint8)((pkgver >> 8) & 0xff);
		obuf[5] = (uint8)(pkgver & 0xff);
		obuf[6] = (uint8)((pkgsize >> 24) & 0xff);
		obuf[7] = (uint8)((pkgsize >> 16) & 0xff);
		obuf[8] = (uint8)((pkgsize >> 8) & 0xff);
		obuf[9] = (uint8)(pkgsize & 0xff);

		obuf[10] = (uint8)0x04;
		obuf[11] = (uint8)'D';
		obuf[12] = (uint8)((Amt >> 8) & 0xff);
		obuf[13] = (uint8)(Amt & 0xff);

		state = SEND_DATA;
		client->setOUsed(FILEHEADERSIZE	+ Amt);
		client->writeNet();
	}
}

void
DownloadPackage::fileEOF()
{
	state = DONE;
	client->getFile()->close();
	client->protocolDone();
}

void
DownloadPackage::fileErr(uint32 Err)    // kharmon.  04-05-07.  #19307.  Change argument to uint32 so that it overrides base class version.
{
	state = DONE;
	client->errmsg(EM_ZipDataError);
}
